package tc.alert.tckejisoc.utils;

import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class CryptoUtils {

    // AES-GCM参数
    private static final int AES_KEY_SIZE = 256;
    private static final int GCM_IV_LENGTH = 12; // bytes
    private static final int GCM_TAG_LENGTH = 16; // bits

    // RSA参数
    private static final int RSA_KEY_SIZE = 2048;
    private static final String RSA_ALGORITHM = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";

    // PBKDF2参数
    private static final int PBKDF2_ITERATIONS = 65536;
    private static final int PBKDF2_KEY_LENGTH = 256;

    /**
     * AES-GCM加密
     * @param plaintext 明文
     * @param key 密钥（Base64编码）
     * @return Base64(IV + ciphertext)
     */
    public static String aesGcmEncrypt(String plaintext, String key) throws CryptoException {
        try {
            // 转换密钥
            SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");

            // 生成随机IV
            byte[] iv = new byte[GCM_IV_LENGTH];
            SecureRandom random = SecureRandom.getInstanceStrong();
            random.nextBytes(iv);

            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);

            byte[] ciphertext = cipher.doFinal(plaintext.getBytes());

            // 合并IV和密文
            byte[] combined = new byte[iv.length + ciphertext.length];
            System.arraycopy(iv, 0, combined, 0, iv.length);
            System.arraycopy(ciphertext, 0, combined, iv.length, ciphertext.length);

            return Base64.getEncoder().encodeToString(combined);
        } catch (Exception e) {
            throw new CryptoException("AES加密失败", e);
        }
    }

    /**
     * AES-GCM解密
     * @param encryptedText Base64(IV + ciphertext)
     * @param key 密钥（Base64编码）
     */
    public static String aesGcmDecrypt(String encryptedText, String key) throws CryptoException {
        try {
            byte[] combined = Base64.getDecoder().decode(encryptedText);

            // 分离IV和密文
            byte[] iv = new byte[GCM_IV_LENGTH];
            byte[] ciphertext = new byte[combined.length - GCM_IV_LENGTH];
            System.arraycopy(combined, 0, iv, 0, iv.length);
            System.arraycopy(combined, iv.length, ciphertext, 0, ciphertext.length);

            SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");

            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            GCMParameterSpec parameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);

            byte[] plaintext = cipher.doFinal(ciphertext);
            return new String(plaintext);
        } catch (Exception e) {
            throw new CryptoException("AES解密失败", e);
        }
    }

    /**
     * 生成AES密钥
     */
    public static String generateAesKey() throws CryptoException {
        try {
            KeyGenerator keyGen = KeyGenerator.getInstance("AES");
            keyGen.init(AES_KEY_SIZE);
            SecretKey secretKey = keyGen.generateKey();
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (Exception e) {
            throw new CryptoException("生成AES密钥失败", e);
        }
    }

    /**
     * RSA公钥加密
     * @param plaintext 明文
     * @param publicKey Base64编码的公钥
     */
    public static String rsaEncrypt(String plaintext, String publicKey) throws CryptoException {
        try {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey key = keyFactory.generatePublic(keySpec);

            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);

            byte[] ciphertext = cipher.doFinal(plaintext.getBytes());
            return Base64.getEncoder().encodeToString(ciphertext);
        } catch (Exception e) {
            throw new CryptoException("RSA加密失败", e);
        }
    }

    /**
     * RSA私钥解密
     * @param encryptedText Base64编码的密文
     * @param privateKey Base64编码的私钥
     */
    public static String rsaDecrypt(String encryptedText, String privateKey) throws CryptoException {
        try {
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey key = keyFactory.generatePrivate(keySpec);

            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);

            byte[] plaintext = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
            return new String(plaintext);
        } catch (Exception e) {
            throw new CryptoException("RSA解密失败", e);
        }
    }

    /**
     * 生成RSA密钥对
     * @return [0]=publicKey, [1]=privateKey
     */
    public static String[] generateRsaKeyPair() throws CryptoException {
        try {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
            keyGen.initialize(RSA_KEY_SIZE);
            KeyPair pair = keyGen.generateKeyPair();

            String[] keys = new String[2];
            keys[0] = Base64.getEncoder().encodeToString(pair.getPublic().getEncoded());
            keys[1] = Base64.getEncoder().encodeToString(pair.getPrivate().getEncoded());
            return keys;
        } catch (Exception e) {
            throw new CryptoException("生成RSA密钥失败", e);
        }
    }

    /**
     * 使用PBKDF2生成密钥
     * @param password 密码
     * @param salt 盐值（Base64编码）
     */
    public static String pbkdf2DeriveKey(String password, String salt) throws CryptoException {
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            KeySpec spec = new PBEKeySpec(
                    password.toCharArray(),
                    Base64.getDecoder().decode(salt),
                    PBKDF2_ITERATIONS,
                    PBKDF2_KEY_LENGTH
            );
            SecretKey secretKey = factory.generateSecret(spec);
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (Exception e) {
            throw new CryptoException("PBKDF2密钥生成失败", e);
        }
    }

    /**
     * 生成安全随机盐值
     */
    public static String generateSalt() {
        byte[] salt = new byte[16];
        new SecureRandom().nextBytes(salt);
        return Base64.getEncoder().encodeToString(salt);
    }

    public static class CryptoException extends Exception {
        public CryptoException(String message, Throwable cause) {
            super(message, cause);
        }
    }


//    // AES加密示例
//    String aesKey = CryptoUtils.generateAesKey();
//    String encrypted = CryptoUtils.aesGcmEncrypt("敏感数据", aesKey);
//    String decrypted = CryptoUtils.aesGcmDecrypt(encrypted, aesKey);
//
//    // RSA加密示例
//    String[] rsaKeys = CryptoUtils.generateRsaKeyPair();
//    String rsaEncrypted = CryptoUtils.rsaEncrypt("重要信息", rsaKeys[0]);
//    String rsaDecrypted = CryptoUtils.rsaDecrypt(rsaEncrypted, rsaKeys[1]);
//
//    // 密码派生示例
//    String salt = CryptoUtils.generateSalt();
//    String derivedKey = CryptoUtils.pbkdf2DeriveKey("userPassword", salt);
}